package com.message.Volcengine_ai_API.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.ByteStreams;
import com.volcengine.helper.Utils;
import com.volcengine.util.*;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;


public class VolcengineUtil {
    private static final BitSet URLENCODER = new BitSet(256);
    private static final String CONST_ENCODE = "0123456789ABCDEF";
    public static final Charset UTF_8 = StandardCharsets.UTF_8;
    private  String region;
    private  String service;
    private  String schema;
    private  String host;
    private  String path;
    private  String ak;
    private  String sk;

    static {
        int i;
        for (i = 97; i <= 122; ++i) {
            URLENCODER.set(i);
        }
        for (i = 65; i <= 90; ++i) {
            URLENCODER.set(i);
        }
        for (i = 48; i <= 57; ++i) {
            URLENCODER.set(i);
        }
        URLENCODER.set('-');
        URLENCODER.set('_');
        URLENCODER.set('.');
        URLENCODER.set('~');
    }
    public static String toJsonString(Map<String, ?> map) {
        return new org.json.JSONObject(map).toString();
    }

    public VolcengineUtil(String region, String service, String schema, String host, String path, String ak, String sk) {
        this.region = region;
        this.service = service;
        this.host = host;
        this.schema = schema;
        this.path = path;
        this.ak = ak;
        this.sk = sk;
    }

    public List<String> doRequest(String method, Map<String, String> queryList, byte[] body, Date date, String action, String version) throws Exception {
        if (body == null) {
            body = new byte[0];
        }
        String xContentSha256 = hashSHA256(body);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String xDate = sdf.format(date);
        String shortXDate = xDate.substring(0, 8);
        String contentType = "application/json";
        String signHeader = "host;x-date;x-content-sha256;content-type";

        SortedMap<String, String> realQueryList = new TreeMap<>(queryList);
        realQueryList.put("Action", action);
        realQueryList.put("Version", version);
        StringBuilder querySB = new StringBuilder();
        for (String key : realQueryList.keySet()) {
            querySB.append(signStringEncoder(key)).append("=").append(signStringEncoder(realQueryList.get(key))).append("&");
        }
        querySB.deleteCharAt(querySB.length() - 1);

        String canonicalStringBuilder = method + "\n" + path + "\n" + querySB + "\n" +
                "host:" + host + "\n" +
                "x-date:" + xDate + "\n" +
                "x-content-sha256:" + xContentSha256 + "\n" +
                "content-type:" + contentType + "\n" +
                "\n" +
                signHeader + "\n" +
                xContentSha256;

        System.out.println(canonicalStringBuilder);

        String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
        String credentialScope = shortXDate + "/" + region + "/" + service + "/request";
        String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;

        byte[] signKey = genSigningSecretKeyV4(sk, shortXDate, region, service);
//        String signature = HexFormat.of().formatHex(hmacSHA256(signKey, signString));
        String signature = Hex.encodeHexString(Utils.hmacSHA256(signKey, signString));

        URL url = new URL(schema + "://" + host + path + "?" + querySB);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod(method);
        conn.setRequestProperty("Host", host);
        conn.setRequestProperty("X-Date", xDate);
        conn.setRequestProperty("X-Content-Sha256", xContentSha256);
        conn.setRequestProperty("Content-Type", contentType);
        conn.setRequestProperty("Authorization", "HMAC-SHA256" +
                " Credential=" + ak + "/" + credentialScope +
                ", SignedHeaders=" + signHeader +
                ", Signature=" + signature);
        System.out.println("Authorization Header: " + "HMAC-SHA256" +
                " Credential=" + ak + "/" + credentialScope +
                ", SignedHeaders=" + signHeader +
                ", Signature=" + signature); // 添加这行代码进行调试
        if (!Objects.equals(conn.getRequestMethod(), "GET")) {
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            os.write(body);
            os.flush();
            os.close();
        }
        conn.connect();

        int responseCode = conn.getResponseCode();

        InputStream is;
        if (responseCode == 200) {
            is = conn.getInputStream();
        } else {
            is = conn.getErrorStream();
        }
//        String responseBody = new String(ByteStreams.toByteArray(is));
        String responseBody = readResponse(conn, responseCode);
       List<String> base64Data = extractBase64FromResponse(responseBody);
        is.close();

        return base64Data;
    }

    public Map<String, Object> doRequestInMap(String method, Map<String, String> queryList, byte[] body, Date date, String action, String version) throws Exception {
        if (body == null) {
            body = new byte[0];
        }
        String xContentSha256 = hashSHA256(body);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        String xDate = sdf.format(date);
        String shortXDate = xDate.substring(0, 8);
        String contentType = "application/json";
        String signHeader = "host;x-date;x-content-sha256;content-type";

        SortedMap<String, String> realQueryList = new TreeMap<>(queryList);
        realQueryList.put("Action", action);
        realQueryList.put("Version", version);
        StringBuilder querySB = new StringBuilder();
        for (String key : realQueryList.keySet()) {
            querySB.append(signStringEncoder(key)).append("=").append(signStringEncoder(realQueryList.get(key))).append("&");
        }
        querySB.deleteCharAt(querySB.length() - 1);

        String canonicalStringBuilder = method + "\n" + path + "\n" + querySB + "\n" +
                "host:" + host + "\n" +
                "x-date:" + xDate + "\n" +
                "x-content-sha256:" + xContentSha256 + "\n" +
                "content-type:" + contentType + "\n" +
                "\n" +
                signHeader + "\n" +
                xContentSha256;

        System.out.println(canonicalStringBuilder);

        String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
        String credentialScope = shortXDate + "/" + region + "/" + service + "/request";
        String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;

        byte[] signKey = genSigningSecretKeyV4(sk, shortXDate, region, service);
//        String signature = HexFormat.of().formatHex(hmacSHA256(signKey, signString));
        String signature = Hex.encodeHexString(Utils.hmacSHA256(signKey, signString));

        URL url = new URL(schema + "://" + host + path + "?" + querySB);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod(method);
        conn.setRequestProperty("Host", host);
        conn.setRequestProperty("X-Date", xDate);
        conn.setRequestProperty("X-Content-Sha256", xContentSha256);
        conn.setRequestProperty("Content-Type", contentType);
        conn.setRequestProperty("Authorization", "HMAC-SHA256" +
                " Credential=" + ak + "/" + credentialScope +
                ", SignedHeaders=" + signHeader +
                ", Signature=" + signature);
//        conn.setRequestProperty("Authorization", "HMAC-SHA256 Credential=AKLTOWYxNmFkMmE3NDBhNDU4Mjg3YTEzYzRhMWMzY2I4ODI/20241228/cn-north-1/iam/request, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature="+signature);
        System.out.println("Authorization Header: " + "HMAC-SHA256" +
                " Credential=" + ak + "/" + credentialScope +
                ", SignedHeaders=" + signHeader +
                ", Signature=" + signature); // 添加这行代码进行调试
        if (!Objects.equals(conn.getRequestMethod(), "GET")) {
            conn.setDoOutput(true);
            OutputStream os = conn.getOutputStream();
            os.write(body);
            os.flush();
            os.close();
        }
        conn.connect();

        int responseCode = conn.getResponseCode();

        InputStream is;
        if (responseCode == 200) {
            is = conn.getInputStream();
        } else {
            is = conn.getErrorStream();
        }
//        String responseBody = new String(ByteStreams.toByteArray(is));
        String responseBody = readResponse(conn, responseCode);
        is.close();
        Map<String,Object> response=new HashMap<>();
        response.put("code",responseCode);
        response.put("body",responseBody);

        return response;
    }

    private String signStringEncoder(String source) {
        if (source == null) {
            return null;
        }
        StringBuilder buf = new StringBuilder(source.length());
        ByteBuffer bb = UTF_8.encode(source);
        while (bb.hasRemaining()) {
            int b = bb.get() & 255;
            if (URLENCODER.get(b)) {
                buf.append((char) b);
            } else if (b == 32) {
                buf.append("%20");
            } else {
                buf.append("%");
                char hex1 = CONST_ENCODE.charAt(b >> 4);
                char hex2 = CONST_ENCODE.charAt(b & 15);
                buf.append(hex1);
                buf.append(hex2);
            }
        }

        return buf.toString();
    }

    public static String hashSHA256(byte[] content) throws Exception {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");


            return Hex.encodeHexString(md.digest(content));
        } catch (Exception e) {
            throw new Exception(
                    "Unable to compute hash while signing request: "
                            + e.getMessage(), e);
        }
    }

    public static byte[] hmacSHA256(byte[] key, String content) throws Exception {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(key, "HmacSHA256"));
            return mac.doFinal(content.getBytes());
        } catch (Exception e) {
            throw new Exception(
                    "Unable to calculate a request signature: "
                            + e.getMessage(), e);
        }
    }

    private byte[] genSigningSecretKeyV4(String secretKey, String date, String region, String service) throws Exception {
        byte[] kDate = hmacSHA256((secretKey).getBytes(), date);
        byte[] kRegion = hmacSHA256(kDate, region);
        byte[] kService = hmacSHA256(kRegion, service);
        return hmacSHA256(kService, "request");
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    private static String readResponse(HttpURLConnection conn, int responseCode) throws Exception {
        try (BufferedReader in = new BufferedReader(new InputStreamReader(
                responseCode >= 400 ? conn.getErrorStream() : conn.getInputStream()))) {
            return in.lines().reduce((a, b) -> a + "\n" + b).orElse("");
        }
    }
    private List<String> extractBase64FromResponse(String responseBody) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            JsonNode rootNode = objectMapper.readTree(responseBody);
            // 检查顶层"data"节点是否存在且非空
            JsonNode dataNode = rootNode.path("data");

            // 获取"data"节点下的"body"
            JsonNode bodyNode = dataNode.path("binary_data_base64");

            List<String> base64Strings = new ArrayList<>();
            for (JsonNode node : bodyNode) {
                String base64String = node.asText();
                // 先移除所有的 [ 和 ]
                base64String = base64String.replaceAll("\\[|\\]", "");   //去除中括号
// 再移除开头和结尾的双引号
                base64String = base64String.replaceAll("^\"|\"$", "");
                base64Strings.add(base64String);
            }

            return base64Strings;
        } catch (IOException e) {
            throw new RuntimeException("Error parsing JSON response: " + e.getMessage(), e);
        }
    }
//    public List<String> doRequestJPcartoonJson(String method, Map<String, String> queryList, byte[] body, Date date, String action, String version) throws Exception {
//        if (body == null) {
//            body = new byte[0];
//        }
//        String xContentSha256 = hashSHA256(body);
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
//        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
//        String xDate = sdf.format(date);
//        String shortXDate = xDate.substring(0, 8);
//        String contentType = "application/x-www-form-urlencoded";
//        String signHeader = "host;x-date;x-content-sha256;content-type";
//
//        SortedMap<String, String> realQueryList = new TreeMap<>(queryList);
//        realQueryList.put("Action", action);
//        realQueryList.put("Version", version);
//
//        // 构建URL编码后的查询字符串
//        StringBuilder querySB = new StringBuilder();
//        for (String key : realQueryList.keySet()) {
//            if (querySB.length() > 0) {
//                querySB.append("&");
//            }
//            querySB.append(URLEncoder.encode(key, "UTF-8"))
//                    .append("=")
//                    .append(URLEncoder.encode(realQueryList.get(key), "UTF-8"));
//        }
//
//        // 构建规范请求字符串
//        String canonicalStringBuilder = method + "\n" + path + "\n" + querySB + "\n" +
//                "host:" + host + "\n" +
//                "x-date:" + xDate + "\n" +
//                "x-content-sha256:" + xContentSha256 + "\n" +
//                "content-type:" + contentType + "\n" +
//                "\n" +
//                signHeader + "\n" +
//                xContentSha256;
//
//        System.out.println(canonicalStringBuilder);
//
//        String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
//        String credentialScope = shortXDate + "/" + region + "/" + service + "/request";
//        String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;
//
//        byte[] signKey = genSigningSecretKeyV4(sk, shortXDate, region, service);
//        String signature = Hex.encodeHexString(Utils.hmacSHA256(signKey, signString));
//
//        URL url = new URL(schema + "://" + host + path + "?" + querySB);
//
//        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//        conn.setRequestMethod(method);
//        conn.setRequestProperty("Host", host);
//        conn.setRequestProperty("X-Date", xDate);
//        conn.setRequestProperty("X-Content-Sha256", xContentSha256);
//        conn.setRequestProperty("Content-Type", contentType);
//        conn.setRequestProperty("Authorization", "HMAC-SHA256" +
//                " Credential=" + ak + "/" + credentialScope +
//                ", SignedHeaders=" + signHeader +
//                ", Signature=" + signature);
//        System.out.println("Authorization Header: " + "HMAC-SHA256" +
//                " Credential=" + ak + "/" + credentialScope +
//                ", SignedHeaders=" + signHeader +
//                ", Signature=" + signature); // 添加这行代码进行调试
//
//        // 如果不是GET请求并且有body，则设置请求体
//        if (!Objects.equals(conn.getRequestMethod(), "GET") && body.length > 0) {
//            conn.setDoOutput(true);
//            try (OutputStream os = conn.getOutputStream()) {
//                os.write(body);
//            }
//        }
//
//        conn.connect();
//
//        int responseCode = conn.getResponseCode();
//
//        InputStream is;
//        if (responseCode == 200) {
//            is = conn.getInputStream();
//        } else {
//            is = conn.getErrorStream();
//        }
//
//        String responseBody = readResponse(conn, responseCode);
//        List<String> base64Data = extractBase64FromResponseJPcartoonJson(responseBody);
//        is.close();
//
//        return base64Data;
//    }
//    private List<String> extractBase64FromResponseJPcartoonJson(String responseBody) throws Exception {
//        ObjectMapper objectMapper = new ObjectMapper();
//
//        try {
//            System.out.println( "ddddddddddddddddddddddddddddddddddddddddddddd"+responseBody);
//            JsonNode rootNode = objectMapper.readTree(responseBody);
//            // 检查顶层"data"节点是否存在且非空
//            JsonNode dataNode = rootNode.path("ResponseMetadata");
//
//            // 获取"data"节点下的"body"
//            JsonNode bodyNode = dataNode.path("image");
//
//            List<String> base64Strings = new ArrayList<>();
//            for (JsonNode node : bodyNode) {
//                String base64String = node.asText();
//                // 先移除所有的 [ 和 ]
//                base64String = base64String.replaceAll("\\[|\\]", "");   //去除中括号
//// 再移除开头和结尾的双引号
//                base64String = base64String.replaceAll("^\"|\"$", "");
//                base64Strings.add(base64String);
//            }
//
//            return base64Strings;
//        } catch (IOException e) {
//            throw new RuntimeException("Error parsing JSON response: " + e.getMessage(), e);
//        }
//    }
}
